﻿/*
Copyright (c) 2010, hiSoft
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the hiSoft nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE HISOFT AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL HISOFT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;

namespace Orchard.Test.Library
{
    public class BlogHelper : UIHelperBase
    {
        public BlogHelper(TestLibrary settings) : base(settings) { }

        private void InputBlogSetting(BlogSettings blogSetting)
        {
            selenium.Type("Routable_Title", blogSetting.Title);
            selenium.Type("Routable_Slug", blogSetting.Permalink);
            selenium.Type("Description", blogSetting.Description);
            if (blogSetting.OnMainMenu)
            {
                selenium.Check("OnMainMenu");
                selenium.Type("MenuText", blogSetting.MenuText);
            }
            else
            {
                selenium.Uncheck("OnMainMenu");
            }
            if (blogSetting.OnAdminMenu)
            {
                selenium.Check("OnAdminMenu");
                selenium.Type("AdminMenuText", blogSetting.AdminMenuText);
                selenium.Type("AdminMenuPosition", blogSetting.AdminMenuPosition);
            }
            else
            {
                selenium.Uncheck("OnAdminMenu");
            }
            if (blogSetting.SetAsHomePage)
            {
                selenium.Check("Routable_PromoteToHomePage");
            }
            else
            {
                selenium.Uncheck("Routable_PromoteToHomePage");
            }

            if (blogSetting.Owner != TestLibrary.Consts.AdminUserName)
            {
                selenium.Type(OwnerLocator, blogSetting.Owner);
            }
            Submit();
            var blog = new Blog(TestSettings, blogSetting);
            if (selenium.IsTextPresent("Slugs in conflict."))
            {
                DoActionToBlog(blog, BlogAction.Edit);
                blogSetting.Permalink = selenium.GetValue("Routable_Slug");
            }
        }

        private int GetBlogIndexOnManageBlogsPage(Blog blog)
        {
            var count = GetBlogsCount(); ;
            var index = 1;
            for (; index <= count; ++index)
            {
                string path = String.Format("{0}[{1}]/div/div/h3/a", BlogsLocator, index);
                var text = selenium.GetText(path);
                if (String.CompareOrdinal(blog.Title, text) == 0)
                    break;
            }

            if (index > count)
                throw new CaseFailureException(String.Format("Can't find blog {0} in manage blogs page!", blog.Title));

            return index;
        }

        private int GetActionIndexByText(int blogIndex, string actionText)
        {
            string actionsLocator = String.Format("{0}[{1}]/div/div[2]/a", BlogsLocator, blogIndex);
            int actionsCount = (int)selenium.GetXpathCount(actionsLocator);
            for (int i = 1; i <= actionsCount; i++)
            {
                if (selenium.GetText(String.Format("{0}[{1}]", actionsLocator, i)) == actionText)
                {
                    return i;
                }
            }
            return -1;
        }

        public void ManageBlogs()
        {
            selenium.Open("/Admin/Blogs");             
        }

        public void ViewDefaultTestBlog()
        {
           if(!selenium.GetLocation().EndsWith("/default-test-blog"))
            selenium.Open("/default-test-blog");
        }

        public void ViewDefaultTestPost()
        {
            if (!selenium.GetLocation().EndsWith("/default-test-blog/default-test-post"))
                selenium.Open("/default-test-blog/default-test-post");
        }

        public bool IsBlogPresent(Blog blog)
        {
            ManageBlogs();
            return selenium.IsTextPresent(blog.Title);
        }

        public bool IsPostPresentByContent_DefaultTestBlog(string postContent)
        {
            ViewDefaultTestBlog();
            return selenium.IsTextPresent(postContent);
        }

        public bool IsPostPresentByTitle(string postTitle,string blogName)
        {
            ManageBlogs();
            ClickAndWait(string.Format("link={0}",blogName));
            return selenium.IsElementPresent(string.Format("link={0}",postTitle));
        }

        public bool IsPublishPostLaterOK_DefaultTestBlog(string postContent,bool isLogon)
        {
            ViewDefaultTestBlog();
            int index = GetPostIndexByContent(postContent,isLogon);
            bool result = true;
            string postPublishDatetime = "";
            if (index < 1) result= false;
            else
            {
                if(isLogon) postPublishDatetime = selenium.GetText("//div[@id='content']/div/div/article/ul/li/div/article/header/div/div");
                else postPublishDatetime = selenium.GetText("//div[@id='content']/div/article/ul/li/article/header/div/div");
                string postPublishTimeMinutes = postPublishDatetime.Substring(postPublishDatetime.IndexOf(':')+1, 2);
                string editPostTimeMinutes = postContent.Substring(postContent.IndexOf(':')+1,2);
                if (int.Parse(postPublishTimeMinutes) >= int.Parse(editPostTimeMinutes) + 1 && int.Parse(postPublishTimeMinutes) <= int.Parse(editPostTimeMinutes) + 2)
                    result = true;
            }
            return result;
        }

        public int GetPostsCount_DefaultTestBlog(bool isLogon)
        {            
            ViewDefaultTestBlog();
            //if LogonasAdmin  //div[@id='content']/div/div/article/ul/li  else not logon: //div[@id='content']/div/article/ul/li
            int count=0;
            if (isLogon)
            {
                if (selenium.IsElementPresent("//div[@id='content']/div/div/article/ul/li"))
                   count=(int)selenium.GetXpathCount("//div[@id='content']/div/div/article/ul/li");
            }
            else 
            {
                if (selenium.IsElementPresent("//div[@id='content']/div/article/ul/li"))
                    count=(int)selenium.GetXpathCount("//div[@id='content']/div/article/ul/li");
            }
            return count;
        }

        public int GetPostIndexByContent(string postContent,bool isLogon)
        {
            int postCount_DefaultTestBlog = GetPostsCount_DefaultTestBlog(isLogon);
            string locator_postContent="";
            int result=0;
            if (postCount_DefaultTestBlog > 0)
            {
                for (int i = 1; i < postCount_DefaultTestBlog; i++)
                {
                    if(isLogon)locator_postContent=string.Format("//div[@id='content']/div/div/article/ul/li[{0}]",i);
                    else locator_postContent = string.Format("//div[@id='content']/div/article/ul/li[{0}]", i);
                    if (selenium.GetText(locator_postContent).Contains(postContent))
                    { result = i; break; }
                }
            }
            return result;
        }

        public int GetBlogsCount()
        {
            ManageBlogs();
            int blogsCount = 0;
            if (selenium.IsElementPresent(BlogsLocator))
            {
                blogsCount = (int)selenium.GetXpathCount(BlogsLocator);
            }
            else if (selenium.IsElementPresent("//fieldset[@class='contentItems bulk-items']/div/ul/li"))
            {
                blogsCount = (int)selenium.GetXpathCount("//fieldset[@class='contentItems bulk-items']/div/ul/li"); 
            }
            return blogsCount;            
        }

        public int GetPostIndexOnViewArchiveForm(string strPostTitle)
        {
            int postCount =(int) selenium.GetXpathCount("//div[@id='content']/div/ul/li");
            int i = 1;
            int result=0;
            string locator="";
            //string locator = string.Format("//div[@id='content']/div/ul/li[{0}]/article/header/h1/a", i);  //if not log in, there is no "div" before "article"            
            for (; i <= postCount; i++)
            {
                locator = string.Format("//div[@id='content']/div/ul/li[{0}]/div/article/header/h1/a", i);  // when log in website
                if (selenium.IsElementPresent(locator))
                {
                    if (strPostTitle == selenium.GetText(locator))
                    result= i;
                }
            }           
            return result;            
        }

        public DateTime GetPublishDateTimeOfPostOnViewArchiveForm(string  strPostTitle)
        {
            int postIndexInViewArchiveForm = GetPostIndexOnViewArchiveForm(strPostTitle);
            string datetime = selenium.GetText(string.Format("//div[@id='content']/div/ul/li[{0}]/div/article/header/div/div", postIndexInViewArchiveForm));
            DateTime dt = DateTime.Parse(datetime);
            return dt;
        }

        public DateTime GetPublishDateTimeOfPostOnViewArchiveForm(int postIndexInViewArchiveForm)
        {
           string datetime= selenium.GetText(string.Format("//div[@id='content']/div/ul/li[{0}]/div/article/header/div/div",postIndexInViewArchiveForm));
           DateTime dt = DateTime.Parse(datetime);
           return dt;
        }

        public Blog CreateRandomBlog()
        {            
            return CreateBlog(new BlogSettings());
        }     

        public Blog CreateBlog(BlogSettings blogSetting)
        {  
            selenium.Open("/Admin/Blogs/Create");
            InputBlogSetting(blogSetting);
            return new Blog(TestSettings, blogSetting);
        }

        public Blog EditBlog(Blog blog, BlogSettings newSetting)
        {
            DoActionToBlog(blog, BlogAction.Edit);
            InputBlogSetting(newSetting);
            return new Blog(TestSettings, newSetting);
        }        

        public void DoActionToBlog(Blog blog, BlogAction action)
        {
            int blogIndex = GetBlogIndexOnManageBlogsPage(blog);
            string actionText = null;
            switch (action)
            {
                case BlogAction.Edit:
                    actionText = "Edit";                                
                    break;
                case BlogAction.ListPosts:
                    actionText = "List Posts";                              
                    break;
                case BlogAction.NewPost:
                    actionText = "New Post";                              
                    break;
                case BlogAction.Delete:
                    actionText = "Delete";                            
                    break;
                case BlogAction.View:
                    actionText = "View";        
                    break;
                case BlogAction.Unpublish:
                    actionText = "Unpublish";
                    break;
                case BlogAction.Publish:
                    actionText = "Publish";
                    break;           
            }
            int actionIndex = GetActionIndexByText(blogIndex, actionText);
            ClickAndWait(String.Format("{0}[{1}]/div/div[2]/a[{2}]", BlogsLocator, blogIndex, actionIndex));            
        }

        public void SelectDeleteBlog(Blog blog)
        {
            int index = GetBlogIndexOnManageBlogsPage(blog);
            selenium.Check(String.Format("{0}[{1}]/div/div/input[@type='checkbox']", BlogsLocator, index));
            selenium.Select("publishActions", "label=Delete");
            Submit();
        }

        public string GetOwnerOfBlog(Blog blog)
        {
            int index = GetBlogIndexOnManageBlogsPage(blog);
            string ownerStr = selenium.GetText(String.Format("{0}[{1}]/div/div/div/ul/li[2]", BlogsLocator, index));
            return ownerStr.Split(' ')[1];           
        }

        public string GetPublishStatusOfBlog(Blog blog)
        {
            ManageBlogs();
            int index = GetBlogIndexOnManageBlogsPage(blog);
            if (selenium.GetText(string.Format("{0}[{1}]/div/div[2]/a[2]", BlogsLocator, index)) == "Unpublish")
                return "Publish";
            else return "Unpublish";
        }
      
        public void ChangeBlogSlug(Blog blog,string newSlug)
        {
            DoActionToBlog(blog, BlogAction.Edit); 
            selenium.Type("Routable_Slug", newSlug);
            Submit();       
        }

        public void ChangeBodyFlavorOfPost(string flavor)
        {
            selenium.Open("/Admin/ContentTypes/Edit/BlogPost");
            selenium.Click("//fieldset[@itemid='BodyPart']/h3/span/span");
            selenium.Type("//fieldset[@itemid='BodyPart']/div[2]/div/fieldset/input", flavor);
            Submit();
        }
              

    }

    public class BlogSettings
    {
        public string Title { get; set; }

        public string Permalink { get; set; }

        public bool SetAsHomePage { get; set; }

        public string Description { get; set; }

        public bool OnMainMenu { get; set; }

        public string MenuText { get; set; }

        public bool OnAdminMenu { get; set; }

        public string AdminMenuText { get; set; }

        public string AdminMenuPosition { get; set; }

        public string Owner { get; set; }

        public BlogSettings()
        {
            string uniqueIdentifier = UIHelperBase.GenerateUniqueIdentifier(DateTime.Now);
            Title = String.Format("Blog {0}", uniqueIdentifier);
            Permalink = String.Format("blog-{0}", uniqueIdentifier);
            Owner = TestLibrary.Consts.AdminUserName;
        }
    }

    public enum BlogAction
    {
        View,
        ListPosts,
        NewPost,
        Edit,
        Unpublish,
        Publish,
        Delete
    }
}
